package com.aforce3.trailertracer;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.media.j3d.Transform3D;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import com.aforce3.trailertracer.particles.Particle;
import com.aforce3.trailertracer.scenes.PointLight;
import com.aforce3.trailertracer.scenes.Rectangle;
import com.aforce3.trailertracer.scenes.SceneGroup;
import com.aforce3.trailertracer.scenes.Sphere;
import com.aforce3.trailertracer.scenes.Triangle;

public class SceneFactory
{
	public static List<Frame> getStaticScene001()
	{
		List<Frame> frames = new ArrayList<Frame>();
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup();

		// scene.add(new Triangle(new Point3d(-100 + 300, 100 + 300, -400), new Point3d(100 + 300, 100 + 300, -400), new Point3d(0 + 300, -50 + 300, -800)));

		Triangle top = new Triangle(new Point3d(-1, 2.2f, -3), new Point3d(1, 2.2f, -3), new Point3d(0, 2.2f, -6));
		Material m = new Material(new Color3f(1f, 0f, 0f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 0, 0), 1, 30);
		top.setMaterial(m);

		scene.add(top);

		scene.add(new Sphere(new Point3d(0, 0, -7), 2f));

		Sphere s1 = new Sphere(new Point3d(3f, 0f, -6), 0.3f);
		Material cover = new Material(new Color3f(0.1f, 0.1f, 0.1f), new Color3f(0, 0, 0), new Color3f(0.2f, 0.2f, 0.2f), new Color3f(1, 1, 1), 0, 30);
		s1.setMaterial(cover);
		Sphere s2 = new Sphere(new Point3d(3f, 0f, -5), 0.3f);
		s2.setMaterial(cover);

		scene.add(s1);
		scene.add(s2);

		// Triangle close = new Triangle(new Point3d(10, 10, -800), new Point3d(15, 10, -400), new Point3d(10, 15, -400));
		// close.setMaterial(m);
		// scene.add(close);

		PointLight l = new PointLight(new Point3d(-1.5f, 1.5f, -5), 0.3f, 0.6f);
		Material yellow = new Material(new Color3f(1, 1, 0), new Color3f(1, 1, 0), new Color3f(1, 1, 0), new Color3f(1, 1, 1), 1, 30);
		l.setMaterial(yellow);

		PointLight b = new PointLight(new Point3d(1.5f, -1.5f, -5), 0.3f, 0.6f);
		Material blue = new Material(new Color3f(0, 1, 1), new Color3f(0, 1, 1), new Color3f(0, 1, 1), new Color3f(0, 1, 1), 1, 30);
		b.setMaterial(blue);

		scene.add(l);

		scene.add(b);

		Triangle tt = new Triangle(new Point3d(-1, -1, 0), new Point3d(1, -1, 0), new Point3d(0, 1, 0));
		tt.setMaterial(cover);

		Transform3D trans = new Transform3D();
		trans.set(new Vector3d(0, -1, -3));
		tt.SetTranform(trans);

		// tt.applyTransforms();

		scene.add(tt);

		scene.applyTransform();

		Camera camera = new Camera(new Point3d(0, 0, 10), new Point3d(0, 0, -1), new Vector3d(0, 1, 0));

		frames.add(new Frame(image, camera, scene));

		return frames;
	}

	public static List<Frame> getStaticScene002()
	{
		List<Frame> frames = new ArrayList<Frame>();
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup();

		int roomdepth = 40;

		scene.add(new Sphere(new Point3d(0, 0, -10), 1.7f));

		PointLight l = new PointLight(new Point3d(1f, -1f, -8), 0.3f, 0.6f);
		Material lightMaterial = new Material(new Color3f(0, 1, 1), new Color3f(0.3f, 0.1f, 0.5f), new Color3f(0, 1, 1), new Color3f(1, 1, 1), 0.4f, 1);
		l.setMaterial(lightMaterial);

		scene.add(l);

		{
			Material m = new Material(new Color3f(1, 0.2f, 0.2f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 0.5f, 1);
			Rectangle close = new Rectangle(new Point3d(-10, 10, 0), new Point3d(10, 10, 0), new Point3d(10, 10, -roomdepth), new Point3d(-10, 10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(1, 1, 0.2f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 0.5f, 1);
			Rectangle close = new Rectangle(new Point3d(-10, 10, 0), new Point3d(-10, -10, 0), new Point3d(-10, -10, -roomdepth), new Point3d(-10, 10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(1, 0.2f, 1), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 0.5f, 1);
			Rectangle close = new Rectangle(new Point3d(-10, -10, 0), new Point3d(10, -10, 0), new Point3d(10, -10, -roomdepth), new Point3d(-10, -10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(0, 0, 1), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 0.5f, 1);
			Rectangle close = new Rectangle(new Point3d(10, -10, 0), new Point3d(10, 10, 0), new Point3d(10, 10, -roomdepth), new Point3d(10, -10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(1, 1, 1), new Color3f(1, 1, 1), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 0.5f, 1);
			Rectangle close = new Rectangle(new Point3d(-10, 10, -roomdepth), new Point3d(10, 10, -roomdepth), new Point3d(10, -10, -roomdepth), new Point3d(-10, -10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		Camera camera = new Camera(new Point3d(0, 0, 10), new Point3d(0, 0, -1), new Vector3d(0, 1, 0));

		frames.add(new Frame(image, camera, scene));

		return frames;
	}

	/** Clearly demonstrates a couple of bugs, including reflection through an object. **/
	public static List<Frame> getStaticScene003()
	{
		List<Frame> frames = new ArrayList<Frame>();
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup();

		int roomdepth = 40;

		scene.add(new Sphere(new Point3d(0, 0, -10), 3.7f));

		{
			Material m = new Material(new Color3f(1, 0.2f, 0.2f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 1, 1);
			Rectangle close = new Rectangle(new Point3d(-10, 10, 0), new Point3d(10, 10, 0), new Point3d(10, 10, -roomdepth), new Point3d(-10, 10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(1, 1, 0.2f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 1, 1);
			Rectangle close = new Rectangle(new Point3d(-10, 10, 0), new Point3d(-10, -10, 0), new Point3d(-10, -10, -roomdepth), new Point3d(-10, 10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(1, 0.2f, 1), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 1, 1);
			Rectangle close = new Rectangle(new Point3d(-10, -10, 0), new Point3d(10, -10, 0), new Point3d(10, -10, -roomdepth), new Point3d(-10, -10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(0, 0, 1), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 1, 1);
			Rectangle close = new Rectangle(new Point3d(10, -10, 0), new Point3d(10, 10, 0), new Point3d(10, 10, -roomdepth), new Point3d(10, -10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		{
			Material m = new Material(new Color3f(1, 1, 1), new Color3f(1, 1, 1), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 1, 1);
			Rectangle close = new Rectangle(new Point3d(-10, 10, -roomdepth), new Point3d(10, 10, -roomdepth), new Point3d(10, -10, -roomdepth), new Point3d(-10, -10, -roomdepth));
			close.setMaterial(m);
			scene.add(close);
		}

		Camera camera = new Camera(new Point3d(0, 0, 10), new Point3d(0, 0, -1), new Vector3d(0, 1, 0));

		frames.add(new Frame(image, camera, scene));

		return frames;
	}

	public static List<Frame> getStaticScene004()
	{
		List<Frame> frames = new ArrayList<Frame>();
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup(new Point3d(-12, 12, -36), new Point3d(12, -12, -24));

		Sphere s = new Sphere(new Point3d(0, 0, -30), 2f);
		Material m = new Material(new Color3f(1f, 0.2f, 0.2f), new Color3f(0f, 0f, 0f), new Color3f(0.3f, 0f, 0f), new Color3f(1, 1, 1), 0.5f, 30);
		s.setMaterial(m);
		scene.add(s);

		Sphere s2 = new Sphere(new Point3d(-4, 0, -25), 2f);
		Material m2 = new Material(new Color3f(1f, 0.2f, 0.2f), new Color3f(0f, 0f, 0f), new Color3f(0.3f, 0f, 0f), new Color3f(1, 1, 1), 0.5f, 30);
		s2.setMaterial(m2);
		scene.add(s2);

		PointLight s3 = new PointLight(new Point3d(4, 0, -25), 0.2f, 0.6f);
		Material m3 = new Material(new Color3f(1, 1f, 0.2f), new Color3f(1, 1, 0), new Color3f(1, 0, 0), new Color3f(1f, 1f, 1f), 1, 30);

		s3.setMaterial(m3);
		scene.add(s3);

		// strips
		Material m4 = new Material(new Color3f(0, 0.3f, 0.3f), new Color3f(0, 0, 0), new Color3f(0, 0.3f, 0.3f), new Color3f(1f, 1f, 1f), 1, 30);
		Rectangle r;
		for(float i = 0; i < 10; i++)
		{
			r = new Rectangle(new Point3d(-10 + 2 * i, -10, -35), new Point3d(-10 + 2 * i, 10, -35), new Point3d(-9 + 2 * i, 10, -35), new Point3d(-9 + 2 * i, -10, -35));
			r.setMaterial(m4);
			scene.add(r);
		}

		Material m5 = new Material(new Color3f(1f, 1f, 1f), new Color3f(1, 1, 1), new Color3f(1, 1, 1), new Color3f(1f, 1f, 1f), 1, 30);
		PointLight s5 = new PointLight(new Point3d(-4, 0, -28.5), 0.2f, 0.6f);
		s5.setMaterial(m5);
		scene.add(s5);

		// scene.add(b);

		Camera camera = new Camera(new Point3d(0, 0, 10), new Point3d(0, 0, -1), new Vector3d(0, 1, 0));

		frames.add(new Frame(image, camera, scene));

		return frames;
	}

	public static List<Frame> getStaticScene005()
	{
		List<Frame> frames = new ArrayList<Frame>();
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup();

		Sphere s = new Sphere(new Point3d(0, 0, -30), 2f);
		Material m = new Material(new Color3f(0.1f, 0.1f, 0.1f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 0.5f, 30);
		s.setMaterial(m);
		scene.add(s);

		Sphere s2 = new Sphere(new Point3d(-4, 0, -25), 2f);
		Material m2 = new Material(new Color3f(1, 0.2f, 0.2f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 0.5f, 30);
		s2.setMaterial(m2);
		scene.add(s2);

		PointLight s3 = new PointLight(new Point3d(4, 0, -25), 0.2f, 0.6f);
		Material m3 = new Material(new Color3f(1, 1f, 0.2f), new Color3f(1, 1, 0), new Color3f(1, 0, 0), new Color3f(0.5f, 0.5f, 0.5f), 1, 30);

		s3.setMaterial(m3);
		scene.add(s3);

		double step = (2 * Math.PI) / 10;
		Camera camera = new Camera(new Point3d(-5 * Math.sin(0), 0, -50 * Math.cos(0)), new Point3d(0, 0, -1), new Vector3d(0, 1, 0));

		frames.add(new Frame(image, camera, scene));

		return frames;
	}

	public static List<Frame> getStaticScene006()
	{
		List<Frame> frames = new ArrayList<Frame>();
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup(new Point3d(-2, 2, -2), new Point3d(2, -2, 2));

		for(int i = 0; i < 200; i++)
			scene.add(new Particle(new Point3d(Math.random(), Math.random(), Math.random())));

		Camera camera = new Camera(new Point3d(0, 0, 5), new Point3d(0, 0, 0), new Vector3d(0, 1, 0));

		frames.add(new Frame(image, camera, scene));

		return frames;
	}

	public static List<Frame> getVideoScene001()
	{
		List<Frame> frames = new ArrayList<Frame>();
		for(int i = 0; i < 30; i++)
		{

			BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

			SceneGroup scene = new SceneGroup();

			Triangle top = new Triangle(new Point3d(-1, 2.2f, -3), new Point3d(1, 2.2f, -3), new Point3d(0, 2.2f, -6));
			Material m = new Material(new Color3f(1f, 0f, 0f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 1, 1), 1, 1);
			top.setMaterial(m);

			scene.add(top);

			scene.add(new Sphere(new Point3d(0, 0, -7), 2f));

			Camera camera = new Camera(new Point3d(i * 10, i * 10, 10), new Point3d(0, 0, -1), new Vector3d(0, 1, 0));

			frames.add(new Frame(image, camera, scene));
		}
		return frames;
	}

	/** This is wrong; specular reflection should be red if the light is only red **/
	public static Frame getScene007(double i)
	{
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup();

		Sphere s = new Sphere(new Point3d(0, 0, 0), 2f);
		Material m = new Material(new Color3f(0.1f, 0.1f, 0.1f), new Color3f(0, 0, 0), new Color3f(0.5f, 0.5f, 0.5f), new Color3f(1, 1, 1), 0.5f, 30);
		s.setMaterial(m);
		scene.add(s);

		PointLight s3 = new PointLight(new Point3d(4, 0, -25), 0.2f, 0.6f);
		Material m3 = new Material(new Color3f(1, 0f, 0f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f(1, 0, 0), 1, 30);

		s3.setMaterial(m3);
		
		Transform3D trans = new Transform3D();
		trans.set(new Vector3d(0,0,20));
		
		scene.add(s3);

		Camera camera = new Camera(new Point3d(0, 0, 10), new Point3d(0, 0, 0), new Vector3d(0, 1, 0));

		return new Frame(image, camera, scene);
	}


	/** This is wrong; specular reflection should be red if the light is only red **/
	public static Frame getScene008(double i)
	{
		BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);

		SceneGroup scene = new SceneGroup();

		Sphere s = new Sphere(new Point3d(0, 0, 0), 2f);
		Material m = new Material(new Color3f(0.1f, 0.1f, 0.1f), new Color3f(0, 0, 0), new Color3f(0.5f, 0.5f, 0.5f), new Color3f(1, 1, 1), 0.5f, 30);
		s.setMaterial(m);
		
		scene.add(s);

		PointLight s3 = new PointLight(new Point3d(4, 0, -25), 0.2f, 0.6f);
		Material m3 = new Material(new Color3f(1, 0, 0f), new Color3f(1, 0, 0), new Color3f(1, 0, 0), new Color3f((float)(1-i), (float)i, 0), 1, 30);
		Transform3D rotation = new Transform3D();
		//rotation.rotY(i*Math.PI/2);
		rotation.setTranslation(new Vector3d(-10*i, 0, 0));
		s3.SetTranform(rotation);

		s3.setMaterial(m3);
		scene.add(s3);
		
		scene.applyTransform();

		Camera camera = new Camera(new Point3d(0, 0, 10), new Point3d(0, 0, 0), new Vector3d(0, 1, 0));

		return new Frame(image, camera, scene);
	}
	
	public static List<Frame> getScene009(int t)
	{
		List<Frame> frames = new ArrayList<Frame>();
		BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);

		Vector3d velocity = new Vector3d(0.1, -0.1, 0);
		velocity.scale(t);
		
		Transform3D transformation = new Transform3D();
		transformation.setTranslation(velocity);
		
		SceneGroup scene = new SceneGroup(new Point3d(-12, 12, -36), new Point3d(12, -12, -24));

		Sphere s = new Sphere(new Point3d(0, 0, -30), 2f);
		Material m = new Material(new Color3f(1f, 0.2f, 0.2f), new Color3f(0f, 0f, 0f), new Color3f(0.3f, 0f, 0f), new Color3f(1, 1, 1), 0.5f, 30);
		s.setMaterial(m);
		scene.add(s);
		
		s.SetTranform(transformation);
		

		Sphere s2 = new Sphere(new Point3d(-4, 0, -25), 2f);
		Material m2 = new Material(new Color3f(1f, 0.2f, 0.2f), new Color3f(0f, 0f, 0f), new Color3f(0.3f, 0f, 0f), new Color3f(1, 1, 1), 0.5f, 30);
		s2.setMaterial(m2);
		scene.add(s2);
		
		s2.SetTranform(transformation);
		

		PointLight s3 = new PointLight(new Point3d(4, 0, -25), 0.2f, 0.6f);
		Material m3 = new Material(new Color3f(1, 1f, 0.2f), new Color3f(1, 1, 0), new Color3f(1, 0, 0), new Color3f(1f, 1f, 1f), 1, 30);

		s3.setMaterial(m3);
		scene.add(s3);

		// strips
		Material m4 = new Material(new Color3f(0, 0.3f, 0.3f), new Color3f(0, 0, 0), new Color3f(0, 0.3f, 0.3f), new Color3f(1f, 1f, 1f), 1, 30);
		Rectangle r;
		for(float i = 0; i < 10; i++)
		{
			r = new Rectangle(new Point3d(-10 + 2 * i, -10, -35), new Point3d(-10 + 2 * i, 10, -35), new Point3d(-9 + 2 * i, 10, -35), new Point3d(-9 + 2 * i, -10, -35));
			r.setMaterial(m4);
			scene.add(r);
		}

		Material m5 = new Material(new Color3f(1f, 1f, 1f), new Color3f(1, 1, 1), new Color3f(1, 1, 1), new Color3f(1f, 1f, 1f), 1, 30);
		PointLight s5 = new PointLight(new Point3d(-4, 0, -28.5), 0.2f, 0.6f);
		s5.setMaterial(m5);
		scene.add(s5);

		// scene.add(b);
		
		
		scene.applyTransform();
		Camera camera = new Camera(new Point3d(0, 0, 10), new Point3d(0, 0, -1), new Vector3d(0, 1, 0));

		frames.add(new Frame(image, camera, scene));

		return frames;
	}

}
